<template>
  <!-- 这个类用于进行raycasting（光线投射）。 光线投射用于进行鼠标拾取（在三维空间中计算出鼠标移过了什么物体）。 -->
  <div class="different-faces">
    <div
      id="scene"
      @mousedown="onMouseDown"
      @mouseup="onMouseUp"
      @contextmenu="rightClickOperate"
    ></div>
    <ul
      ref="operateMenu"
      class="operate-menu"
      :style="{ left: operateMenu.left + 'px', top: operateMenu.top + 'px' }"
    >
      <li @click="copyGeometry">复制</li>
      <li @click.self="deleteGeometry">删除</li>
    </ul>
  </div>
</template>

<script>
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

let scene;
let camera;
let renderer;
let controls;

let raycaster;
let mouse;
let selectObject = null;
export default {
  data() {
    return {
      cube: null,
      operateMenu: {
        left: 0,
        top: 0,
      },
      downTime: 0,
      upTime: 0,
      isRightClick: false,
    };
  },
  mounted() {
    this.init();
  },
  computed: {
    windowWidth() {
      return window.innerWidth - 200;
    },
  },
  methods: {
    onMouseDown() {
      this.downTime = new Date().getTime();
      this.$refs.operateMenu.style.display = "none";
    },
    onMouseUp() {
      this.upTime = new Date().getTime();
      this.isRightClick = this.upTime - this.downTime < 300 ? true : false;
    },
    // 点击右键显示右键功能菜单
    rightClickOperate(e) {
      if (this.isRightClick) {
        //排除右键长按情况
        mouse.x = ((e.clientX - 200) / this.windowWidth) * 2 - 1;
        mouse.y = -(e.clientY / window.innerHeight) * 2 + 1;
        raycaster.setFromCamera(mouse, camera);
        const intersects = raycaster.intersectObjects(this.group.children);
        // 输出选中对象
        if (intersects.length > 0) {
          this.$refs.operateMenu.style.display = "block";
          selectObject = intersects[0].object;
          this.renderDiv(e);
        } else {
          this.$refs.operateMenu.style.display = "none";
          selectObject = null;
        }
      }
    },
    copyGeometry() {
      let copyObj = selectObject.clone();
      copyObj.position.x += 5;
      this.group.add(copyObj);
      this.$refs.operateMenu.style.display = "none";
      console.log(camera.position);
    },
    deleteGeometry() {
      this.group.remove(selectObject);
      selectObject = null;
      console.log("删除几何体");
      this.$refs.operateMenu.style.display = "none";
    },
    // 初始化
    init() {
      this.createScene(); // 创建场景
      this.createCube(); // 创建方块
      this.createLight(); // 创建光源
      this.createCamera(); // 创建相机
      this.createRender(); // 创建渲染器
      this.createControls(); // 创建控件对象
      this.render(); // 渲染
    },
    // 创建场景
    createScene() {
      scene = new THREE.Scene();
      //用于简单模拟3个坐标轴的对象.
      //红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.
      scene.add(new THREE.AxesHelper(20));

      raycaster = new THREE.Raycaster();
      mouse = new THREE.Vector2();
    },
    // 创建方块
    createCube() {
      const cubeGeom = new THREE.BoxGeometry(4, 4, 4);
      const sphereGeom = new THREE.SphereGeometry(2);

      this.group = new THREE.Group();
      for (let i = 0; i < 10; i++) {
        const cube = new THREE.Mesh(
          cubeGeom,
          new THREE.MeshPhongMaterial({
            color: new THREE.Color(Math.random(), Math.random(), Math.random()),
          })
        );
        cube.name = "立方体" + i;
        cube.position.set(
          Math.round(Math.random() * 30) - 15,
          Math.round(Math.random() * 30) - 15,
          Math.round(Math.random() * 30) - 20
        );
        this.group.add(cube);

        const sphere = new THREE.Mesh(
          sphereGeom,
          new THREE.MeshPhongMaterial({
            color: new THREE.Color(Math.random(), Math.random(), Math.random()),
          })
        );
        sphere.name = "球体" + i;
        sphere.position.set(
          Math.round(Math.random() * 30) - 15,
          Math.round(Math.random() * 30) - 15,
          Math.round(Math.random() * 30) - 20
        );
        this.group.add(sphere);
      }
      scene.add(this.group);
    },

    // 创建光源
    createLight() {
      // 环境光
      const ambientLight = new THREE.AmbientLight(0xffffff, 0.1); // 创建环境光
      scene.add(ambientLight); // 将环境光添加到场景

      const spotLight = new THREE.SpotLight(0xffffff); // 创建聚光灯
      spotLight.position.set(-20, 40, -10);
      spotLight.castShadow = true;
      scene.add(spotLight);
    },
    // 创建相机
    createCamera() {
      const element = document.getElementById("scene");
      camera = new THREE.PerspectiveCamera(
        35,
        element.clientWidth / element.clientHeight,
        0.1,
        1000
      );
      camera.position.set(0, 30, 30); // 设置相机位置

      camera.lookAt(new THREE.Vector3(0, 0, 0)); // 设置相机方向
      scene.add(camera);
    },
    // 创建渲染器
    createRender() {
      const element = document.getElementById("scene");
      renderer = new THREE.WebGLRenderer();
      renderer.setSize(element.clientWidth, element.clientHeight); // 设置渲染区域尺寸
      renderer.shadowMap.enabled = true; // 显示阴影
      renderer.shadowMap.type = THREE.PCFSoftShadowMap;
      renderer.setClearColor(0x3f3f3f, 1); // 设置背景颜色
      element.appendChild(renderer.domElement);
    },
    render() {
      renderer.render(scene, camera);
      requestAnimationFrame(this.render);
    },
    // 创建控件对象
    createControls() {
      controls = new OrbitControls(camera, renderer.domElement);
    },
    // 更新div的位置
    renderDiv(e) {
      // 显示模型信息
      this.operateMenu.left = e.clientX - 200;
      this.operateMenu.top = e.clientY;
    },
  },
};
</script>
<style lang="less" scoped>
.different-faces {
  width: 100%;
  height: 100%;
  position: relative;
}
#scene {
  width: 100%;
  height: 100%;
}
.operate-menu {
  box-sizing: border-box;
  width: 150px;
  border-radius: 4px;
  padding: 8px 0;
  background-color: #fff;
  box-shadow: 1px 1px 2px 2px rgba(100, 100, 100, 0.5);
  position: absolute;
  display: none;
  li {
    font-size: 13px;
    color: #333;
    padding: 5px 20px;
    cursor: pointer;
    &:hover {
      background-color: #dedede;
    }
  }
}
</style>

